// NetworkSourceLineResolver implements SourceLineResolverInterface and
// SymbolSupplier using a UDP-based network protocol to communicate to a
// server process which handles the lower-level details of loading symbols
// and resolving source info. When used, it must be used simultaneously
// as the SourceLineResolver and SymbolSupplier.
//
// See network_source_line_server.h for a description of the protocol used.
// An implementation of the server side of the protocol is provided there
// as NetworkSourceLineServer.

#ifndef LONGKEY_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_BASE_H_
#define LONGKEY_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_BASE_H_

#include <sys/socket>

#include <map>
#include <set>

namespace longkey_breakpad
{
	using std::string;

	class NetworkSourceLineResolver : public SourceLineResolverInterface,
		public SymbolSupplier
	{
	public:
		// The server and port to connect to, and the
		// maximum time (in milliseconds) to wait for network replies.
		NetworkSourceLineResolver(const string &server,
			unsigned short port,
			int wait_milliseconds);
		// The network interface to connect to, and maximum wait time.
		NetworkSourceLineResolver(NetworkInterface *net,
			int wait_milliseconds);
		virtual ~NetworkSourceLineResolver();

		// SourceLineResolverInterface methods, see source_line_resolver_interface.h
		// for more details.


		// These methods are actually NOOPs in this implementation.
		// The server loads modules as a result of the GetSymbolFile call.
		// Since we're both the symbol supplier and source line resolver,
		// this is an optimization.
		virtual bool LoadModule(const CodeModule *module, const string &map_file);
		virtual bool LoadModuleUsingMapBuffer(const CodeModule *module,
			const string &map_buffer);
		virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module,
			char *memory_buffer);

		// It doesn't matter whether returns true or false, since no memory buffer
		// will be allocated in GetCStringSymbolData().
		virtual bool ShouldDeleteMemoryBufferAfterLoadModule() { return true; }

		void UnloadModule(const CodeModule *module);

		virtual bool HasModule(const CodeModule *module);

		virtual void FillSourceLineInfo(StackFrame *frame);
		virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame);
		virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame);

		// SymbolSupplier methods, see symbol_supplier.h for more details.
		// Note that the server will actually load the symbol data
		// in response to this request, as an optimization.
		virtual SymbolResult GetSymbolFile(const CodeModule *module,
			const SystemInfo *system_info,
			string *symbol_file);
		//FIXME: we'll never return symbol_data here, it doesn't make sense.
		// the SymbolSupplier interface should just state that the supplier
		// *may* fill in symbol_data if it desires, and clients should
		// handle it gracefully either way.
		virtual SymbolResult GetSymbolFile(const CodeModule *module,
			const SystemInfo *system_info,
			string *symbol_file,
			string *symbol_data);
		// Similar as the above GetSymbolFile() method, see the comment above.
		virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
			const SystemInfo *system_info,
			string *symbol_file,
			char **symbol_data);

		// Delete the data buffer allocated in GetCStringSymbolData().
		// Since the above GetCStringSymbolData() won't allocate any memory at all,
		// this method is no-op.
		virtual void FreeSymbolData(const CodeModule *module) { }

	private:
		int wait_milliseconds_;
		// if false, some part of our network setup failed.
		bool initialized_;
		// sequence number of the last request we made
		u_int16_t sequence_;
		NetworkInterface *net_;
		// cached list of loaded modules, so we can quickly answer
		// HasModule requests for modules we've already queried the
		// server about, avoiding another network round-trip.
		std::set<string> module_cache_;
		// cached list of modules for which we don't have symbols,
		// so we can short-circuit that as well.
		std::set<string> no_symbols_cache_;

		// Cached list of source line info, to avoid repeated GET requests
		// for the same frame. In Multithreaded apps that use the same
		// framework across threads, it's pretty common to hit the same
		// exact set of frames in multiple threads.
		// Data is stored in the cache keyed by instruction pointer
		typedef std::map<u_int64_t, StackFrame> SourceCache;
		SourceCache source_line_info_cache_;

		// Cached list of WindowsFrameInfo/CFIFrameInfo, for the same reason.
		// Stored as serialized strings to avoid shuffling around pointers.
		typedef std::map<u_int64_t, string> FrameInfoCache;

		typedef enum {
			kWindowsFrameInfo = 0,
			kCFIFrameInfo = 1,
		} FrameInfoType;
		FrameInfoCache frame_info_cache_[2];

		// Send a message to the server, wait a certain amount of time for a reply.
		// Returns true if a response is received, with the response data
		// in |response|.
		// Returns false if the response times out.
		bool SendMessageGetResponse(const binarystream &message,
			binarystream &response);

		// See if this stack frame is cached, and fill in the source line info
		// if so.
		bool FindCachedSourceLineInfo(StackFrame *frame) const;
		bool FindCachedFrameInfo(const StackFrame *frame,
			FrameInfoType type,
			string *info) const;

		// Save this stack frame in the cache
		void CacheSourceLineInfo(const StackFrame *frame);
		void CacheFrameInfo(const StackFrame *frame,
			FrameInfoType type,
			const string &info);

		// Disallow unwanted copy ctor and assignment operator
		NetworkSourceLineResolver(const NetworkSourceLineResolver&);
		void operator=(const NetworkSourceLineResolver&);
	};
}

#endif	// LONGKEY_BREAKPAD_PROCESSOR_NETWORK_SOURCE_LINE_RESOLVER_BASE_H_